home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 23
/
AACD 23.iso
/
AACD
/
Magazine
/
YAM
/
Source
/
YAM_UT.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-05-11
|
91KB
|
3,027 lines
/***************************************************************************
YAM - Yet Another Mailer
Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
Copyright (C) 2000-2001 by YAM Open Source Team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
YAM Official Support Site : http://www.yam.ch
YAM OpenSource project : http://sourceforge.net/projects/yamos/
$Id: YAM_UT.c,v 1.28 2001/05/11 09:00:00 damato Exp $
***************************************************************************/
#include "YAM.h"
/***************************************************************************
Utilities
***************************************************************************/
/* local protos */
LOCAL int GetWord(char **rptr, char *wbuf, int max);
LOCAL char *ReflowParagraph(char *start, char *end, int lmax, char *dest);
LOCAL char *RemoveQuoteString(char *start, char *end, char *quot, char *dest);
LOCAL char *InsertQuoteString(char *start, char *quote, FILE *out);
LOCAL void SaveParagraph(char *start, char *end, char *prefix, FILE *out);
LOCAL char *FileToBuffer(char *file);
LOCAL int TZtoMinutes(char *tzone);
LOCAL BOOL GetPackMethod(int xpktype, char **method, int *eff);
LOCAL BOOL CompressMailFile(char *src, char *dst, char *passwd, char *method, int eff);
LOCAL BOOL UncompressMailFile(char *src, char *dst, char *passwd);
LOCAL void AppendToLogfile(int id, char *text, void *a1, void *a2, void *a3, void *a4);
LOCAL char *IdentifyFileDT(char *fname);
void SAVEDS ASM putChar(REG(a0, struct Hook *hook), REG(a1, char c), REG(a2, struct Locale *locale));
/*** Requesters ***/
/// StringRequest
// Puts up a string requester
int StringRequest(char *string, int size, char *title, char *body, char *yestext, char *alttext, char *notext, BOOL secret, APTR parent)
{
APTR bt_okay, bt_middle, bt_cancel, wi_sr, st_in;
int ret_code = -1;
wi_sr = WindowObject,
MUIA_Window_Title, title ? title : "YAM",
MUIA_Window_RefWindow, parent,
MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
MUIA_Window_ID, MAKE_ID('S','R','E','Q'),
WindowContents, VGroup,
Child, VGroup,
GroupFrame,
MUIA_Background, MUII_GroupBack,
Child, LLabel(body),
Child, st_in = secret ? MakePassString("") : MakeString(size, ""),
End,
Child, ColGroup(3),
Child, bt_okay = MakeButton(yestext),
Child, bt_middle = alttext ? MakeButton(alttext) : HSpace(0),
Child, bt_cancel = MakeButton(notext),
End,
End,
End;
setstring(st_in, string);
set(wi_sr, MUIA_Window_ActiveObject, st_in);
set(G->App, MUIA_Application_Sleep, TRUE);
DoMethod(G->App, OM_ADDMEMBER, wi_sr);
DoMethod(bt_okay , MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 1);
DoMethod(bt_middle, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 2);
DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 3);
DoMethod(st_in, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, G->App, 2, MUIM_Application_ReturnID, 1);
DoMethod(wi_sr, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, G->App, 2, MUIM_Application_ReturnID, 3);
if (!SafeOpenWindow(wi_sr)) ret_code = 0;
else while (ret_code == -1)
{
ULONG signals;
switch (DoMethod(G->App, MUIM_Application_Input, &signals))
{
case 1: ret_code = 1; break;
case 2: ret_code = 2; break;
case 3: ret_code = 0; break;
}
if (ret_code == -1 && signals) Wait(signals);
}
if (ret_code > 0) GetMUIString(string, st_in);
DoMethod(G->App, OM_REMMEMBER, wi_sr);
set(G->App, MUIA_Application_Sleep, FALSE);
return ret_code;
}
///
/// FolderRequest
// Allows user to choose a folder from a list
struct Folder *FolderRequest(char *title, char *body, char *yestext, char *notext, struct Folder *exclude, APTR parent)
{
static int lastactive;
struct Folder **flist, *folder = (struct Folder *)-1;
int act, i;
char *fname;
APTR bt_okay, bt_cancel, wi_fr, lv_folder;
wi_fr = WindowObject,
MUIA_Window_Title, title ? title : "YAM",
MUIA_Window_RefWindow, parent,
MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
MUIA_Window_ID, MAKE_ID('F','R','E','Q'),
WindowContents, VGroup,
Child, LLabel(body),
Child, lv_folder = ListviewObject,
MUIA_CycleChain, 1,
MUIA_Listview_DoubleClick, TRUE,
MUIA_Listview_List, ListObject,
InputListFrame,
MUIA_List_AutoVisible, TRUE,
End,
End,
Child, ColGroup(3),
Child, bt_okay = MakeButton(yestext),
Child, HSpace(0),
Child, bt_cancel = MakeButton(notext),
End,
End,
End;
if (wi_fr)
{
flist = FO_CreateList();
for (i = 1; i <= (int)*flist; i++) if (flist[i] != exclude) if (flist[i]->Type != FT_SEPARATOR)
DoMethod(lv_folder, MUIM_List_InsertSingle, flist[i]->Name, MUIV_List_Insert_Bottom);
free(flist);
set(lv_folder, MUIA_List_Active, lastactive);
set(wi_fr, MUIA_Window_ActiveObject, lv_folder);
set(G->App, MUIA_Application_Sleep, TRUE);
DoMethod(G->App, OM_ADDMEMBER, wi_fr);
DoMethod(bt_okay , MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 1);
DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 3);
DoMethod(lv_folder, MUIM_Notify, MUIA_Listview_DoubleClick, MUIV_EveryTime, G->App, 2, MUIM_Application_ReturnID, 1);
DoMethod(wi_fr, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, G->App, 2, MUIM_Application_ReturnID, 3);
if (!SafeOpenWindow(wi_fr)) folder = NULL;
else while (folder == (struct Folder *)-1)
{
ULONG signals, oo = DoMethod(G->App, MUIM_Application_Input, &signals);
switch (oo)
{
case 1:
get(lv_folder, MUIA_List_Active, &act);
DoMethod(lv_folder, MUIM_List_GetEntry, act, &fname);
if ((folder = FO_GetFolderByName(fname, NULL))) lastactive = act;
break;
case 3: folder = NULL; break;
}
if (folder == (struct Folder *)-1 && signals) Wait(signals);
}
DoMethod(G->App, OM_REMMEMBER, wi_fr);
set(G->App, MUIA_Application_Sleep, FALSE);
}
return folder;
}
///
/// AttachRequest
// Allows user to select a message part (attachment) from a list
struct Part *AttachRequest(char *title, char *body, char *yestext, char *notext, int winnum, int mode, APTR parent)
{
struct Part *retpart = (struct Part *)-1, *part, *prevpart;
APTR bt_okay, bt_cancel, wi_ar, lv_attach;
wi_ar = WindowObject,
MUIA_Window_Title, title ? title : "YAM",
MUIA_Window_RefWindow, parent,
MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
MUIA_Window_ID, MAKE_ID('A','R','E','Q'),
WindowContents, VGroup,
Child, LLabel(body),
Child, lv_attach = NListviewObject,
MUIA_CycleChain, 1,
MUIA_NListview_NList, NListObject,
InputListFrame,
MUIA_NList_Title, TRUE,
MUIA_NList_DoubleClick, TRUE,
MUIA_NList_MultiSelect, (mode&ATTREQ_MULTI) ? MUIV_NList_MultiSelect_Default : MUIV_NList_MultiSelect_None,
MUIA_NList_DisplayHook, &RE_LV_AttachDspFuncHook,
MUIA_NList_Format, "BAR,BAR,",
End,
End,
Child, ColGroup(3),
Child, bt_okay = MakeButton(yestext),
Child, HSpace(0),
Child, bt_cancel = MakeButton(notext),
End,
End,
End;
if (wi_ar)
{
static struct Part spart[2];
spart[0].Nr = -2; strcpy(spart[0].Name, GetStr(MSG_RE_Original)); spart[0].Size = G->RE[winnum]->Mail.Size; spart[0].Decoded = TRUE;
spart[1].Nr = -1; strcpy(spart[1].Name, GetStr(MSG_RE_AllTexts)); spart[1].Size = 0;
DoMethod(lv_attach, MUIM_NList_InsertSingle, &spart[0], MUIV_NList_Insert_Bottom);
if ((mode&0xF) != ATTREQ_DISP) DoMethod(lv_attach, MUIM_NList_InsertSingle, &spart[1], MUIV_NList_Insert_Bottom);
for (part = G->RE[winnum]->FirstPart->Next; part; part = part->Next)
if ((mode&0xF) != ATTREQ_PRINT || part->Printable) DoMethod(lv_attach, MUIM_NList_InsertSingle, part, MUIV_NList_Insert_Bottom);
// set(lv_attach, MUIA_NList_Active, 1);
set(wi_ar, MUIA_Window_ActiveObject, lv_attach);
set(G->App, MUIA_Application_Sleep, TRUE);
DoMethod(G->App, OM_ADDMEMBER, wi_ar);
DoMethod(bt_okay , MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 1);
DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 3);
DoMethod(lv_attach, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime, G->App, 2, MUIM_Application_ReturnID, 1);
DoMethod(wi_ar, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, G->App, 2, MUIM_Application_ReturnID, 3);
if (!SafeOpenWindow(wi_ar)) retpart = NULL;
else while (retpart == (struct Part *)-1)
{
ULONG signals;
int id;
switch (DoMethod(G->App, MUIM_Application_Input, &signals))
{
case 1:
for (id = MUIV_NList_NextSelected_Start;; prevpart = part)
{
DoMethod(lv_attach, MUIM_NList_NextSelected, &id);
if (id == MUIV_NList_NextSelected_End) break;
DoMethod(lv_attach, MUIM_NList_GetEntry, id, &part);
if (retpart == (struct Part *)-1) retpart = part;
else prevpart->NextSelected = part;
}
break;
case 3: retpart = NULL; break;
}
if (retpart == (struct Part *)-1 && signals) Wait(signals);
}
DoMethod(G->App, OM_REMMEMBER, wi_ar);
set(G->App, MUIA_Application_Sleep, FALSE);
}
return retpart;
}
///
/// InfoWindow
// Displays a text in an own window
void InfoWindow(char *title, char *body, char *oktext, APTR parent)
{
APTR bt_okay, wi_iw;
if ((wi_iw = WindowObject,
MUIA_Window_Title, title,
MUIA_Window_RefWindow, parent,
MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
WindowContents, VGroup,
MUIA_Background, MUII_RequesterBack,
Child, VGroup,
TextFrame,
MUIA_Background, MUII_TextBack,
Child, LLabel(body),
End,
Child, HCenter(bt_okay = MakeButton(oktext)),
End,
End))
{
DoMethod(G->App, OM_ADDMEMBER, wi_iw);
DoMethod(bt_okay, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_MainWindow_CloseWindow, wi_iw);
DoMethod(wi_iw , MUIM_Notify, MUIA_Window_CloseRequest, TRUE, MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_MainWindow_CloseWindow, wi_iw);
set(wi_iw, MUIA_Window_DefaultObject, bt_okay);
set(wi_iw, MUIA_Window_Open, TRUE);
}
}
///
/*** String related ***/
/// itoa
// Converts an integer into a string
char *itoa(int val)
{
static char str[SIZE_SMALL];
sprintf(str, "%ld", val);
return str;
}
///
/// MatchNoCase
// Case insensitive pattern matching
int MatchNoCase(char *string, char *match)
{
char pattern[SIZE_PATTERN];
ParsePatternNoCase(match, pattern, SIZE_PATTERN);
return MatchPatternNoCase(pattern, string);
}
///
/// CompNoCase
// Case insensitive string comparison
BOOL CompNoCase(char *a, char *b, int l)
{
for (; l; l--, a++, b++) if (toupper(*a) != toupper(*b)) return FALSE;
return TRUE;
}
///
/// MatchTT
// Checks if charset matches a translation table
BOOL MatchTT(char *charset, struct TranslationTable *tt, BOOL in)
{
if (!tt) return FALSE;
return (BOOL)MatchNoCase(charset, in ? tt->SourceCharset : tt->DestCharset);
}
////
/// ISpace
// Checks if character is a white-space
BOOL ISpace(char ch)
{
return (BOOL)(ch == ' ' || (ch >= 9 && ch <= 13));
}
///
/// isSpace
// Localized version if isspace()
BOOL isSpace(int c)
{
UBYTE ch = (UBYTE)c;
return (BOOL)(G->Locale ? (IsSpace(G->Locale,(ULONG)ch) != 0) : (isspace(ch) != 0));
}
///
/// isGraph
// Localized version of isgraph()
BOOL isGraph(int c)
{
UBYTE ch = (UBYTE)c;
return (BOOL)(G->Locale ? (IsGraph(G->Locale,(ULONG)ch) != 0) : (isgraph(ch) != 0));
}
///
/// isAlNum
// Localized version of isalnum()
BOOL isAlNum(int c)
{
UBYTE ch = (UBYTE)c;
return (BOOL)(G->Locale ? (IsAlNum(G->Locale,(ULONG)ch) != 0) : (isalnum(ch) != 0));
}
///
/// StripUnderscore
// Removes underscore from button labels
char *StripUnderscore(char *label)
{
if (strchr(label,'_'))
{
static char newlabel[SIZE_DEFAULT];
char *p = newlabel;
for (; *label; label++) if (*label != '_') *p++ = *label;
*p = 0;
return newlabel;
}
else return label;
}
///
/// GetNextLine
// Reads next line from a multi-line string
char *GetNextLine(char *p1)
{
static char *begin;
char *p2;
if (p1) begin = p1;
if ((p1 = strchr(p2 = begin, '\n'))) { *p1 = 0; begin = ++p1; }
return p2;
}
///
/// TrimStart
// Strips leading spaces
char *TrimStart(char *s)
{
while (*s && ISpace(*s)) ++s;
return s;
}
///
/// TrimEnd
// Removes trailing spaces
char *TrimEnd(char *s)
{
char *e = s+strlen(s)-1;
while (e >= s && ISpace(*e)) *e-- = 0;
return s;
}
///
/// Trim
// Removes leading and trailing spaces
char *Trim(char *s)
{
char *e = s+strlen(s)-1;
while (*s && ISpace(*s)) ++s;
while (e >= s && ISpace(*e)) *e-- = 0;
return s;
}
///
/// stccat
// Safe string concatenation
char *stccat(char *a, char *b, int n)
{
int m = 1;
char *p = a;
while (*p) { p++; m++; }
while (*b && m < n) { *p++ = *b++; m++; }
*p = 0;
return a;
}
///
/// stristr
// Case insensitive version of strstr()
char *stristr(char *a, char *b)
{
int l = strlen(b);
for (; *a; a++) if (CompNoCase(a, b, l)) return a;
return NULL;
}
///
/// MyStrChr
// Searches for a character in string, ignoring text in quotes
char *MyStrChr(char *s, int c)
{
BOOL nested = FALSE;
for (; *s; s++)
if (*s == '\"') nested = !nested;
else if (*s == (char)c && !nested) return s;
return NULL;
}
///
/// Index
// Returns position of a character in a string
int Index(char *str, char chr)
{
char *t = strchr(str, chr);
return t ? (int)(t-str) : -1;
}
///
/// AllocStrBuf
// Allocates a dynamic buffer
char *AllocStrBuf(long initlen)
{
// char *strbuf = AllocMem(initlen+4, MEMF_PUBLIC|MEMF_CLEAR);
char *strbuf = calloc(initlen+4,1);
if (strbuf)
{
*((long *)strbuf) = initlen;
return &strbuf[4];
}
return NULL;
}
///
/// FreeStrBuf
// Frees a dynamic buffer
void FreeStrBuf(char *strbuf)
{
long len;
if (!strbuf) return;
len = *((long *)(strbuf-4));
// FreeMem(strbuf-4, len+4);
free(strbuf-4);
}
///
/// StrBufCpy
// Fills a dynamic buffer
char *StrBufCpy(char *strbuf, char *source)
{
long oldlen, newlen;
char *newstrbuf;
if (!strbuf)
if(NULL == (strbuf = AllocStrBuf(strlen(source)+1))) return NULL;
oldlen = *((long *)(strbuf-sizeof(long)));
newstrbuf = strbuf;
for (newlen = oldlen; newlen <= strlen(source); newlen += SIZE_DEFAULT);
if (newlen != oldlen)
{
FreeStrBuf(strbuf);
newstrbuf = AllocStrBuf(newlen);
}
if(newstrbuf) strcpy(newstrbuf, source);
return newstrbuf;
}
///
/// StrBufCat
// String concatenation using a dynamic buffer
char *StrBufCat(char *strbuf, char *source)
{
long oldlen, newlen;
char *newstrbuf;
if (!strbuf)
if(NULL == (strbuf = AllocStrBuf(strlen(source)+1))) return NULL;
oldlen = *((long *)(strbuf-sizeof(long)));
newstrbuf = strbuf;
for (newlen = oldlen; newlen <= strlen(strbuf)+strlen(source); newlen += SIZE_DEFAULT);
if (newlen != oldlen)
{
if(NULL == (newstrbuf = AllocStrBuf(newlen)))
{
FreeStrBuf(strbuf);
return NULL;
}
strcpy(newstrbuf, strbuf);
FreeStrBuf(strbuf);
}
strcat(newstrbuf, source);
return newstrbuf;
}
///
/// FreeData2D
// Frees dynamic two-dimensional array
void FreeData2D(struct Data2D *data)
{
while (data->Used) FreeStrBuf(data->Data[--data->Used]);
if (data->Allocated) free(data->Data);
data->Data = NULL; data->Allocated = 0;
}
///
/// AllocData2D
// Allocates dynamic two-dimensional array
char *AllocData2D(struct Data2D *data, int initsize)
{
if (data->Used >= data->Allocated)
{
data->Allocated += 10;
if (data->Data) data->Data = realloc(data->Data, data->Allocated*sizeof(char *));
else data->Data = malloc(data->Allocated*sizeof(char *));
}
return data->Data[data->Used++] = AllocStrBuf(initsize);
}
///
/// AllocCopy
// Duplicates a memory block
APTR AllocCopy(APTR source, int size)
{
APTR dest;
if ((dest = malloc(size))) memcpy(dest, source, size);
return dest;
}
///
/// Decrypt
// Decrypts passwords
char *Decrypt(char *source)
{
static char buffer[SIZE_PASSWORD+2];
char *write = &buffer[SIZE_PASSWORD];
*write-- = 0;
while (*source)
{
*write-- = ((char)atoi(source))^CRYPTBYTE;
source += 4;
}
return ++write;
}
///
/// Encrypt
// Encrypts passwords
char *Encrypt(char *source)
{
static char buffer[4*SIZE_PASSWORD+2];
char *read = source+strlen(source)-1;
*buffer = 0;
while (read >= source)
{
unsigned char c = (*read--)^CRYPTBYTE;
sprintf(&buffer[strlen(buffer)], "%03d ", c);
}
return buffer;
}
///
/*** File related ***/
/// GetLine
// Gets Null terminated line of a text file
char *GetLine(FILE *fh, char *buffer, int bufsize)
{
char *ptr;
clear(buffer, bufsize);
if (!fgets(buffer, bufsize, fh)) return NULL;
if ((ptr = strpbrk(buffer, "\r\n"))) *ptr = 0;
return buffer;
}
///
/// FileInfo
// Gets size, protection bits and type of a file/directory
BOOL FileInfo(char *filename, int *size, long *bits, long *type)
{
struct FileInfoBlock *fib;
BPTR lock;
if ((lock = Lock((STRPTR)filename,ACCESS_READ)))
{
fib = AllocDosObject(DOS_FIB, NULL);
Examine(lock, fib);
if (size) *size = fib->fib_Size;
if (bits) *bits = fib->fib_Protection;
if (type) *type = fib->fib_DirEntryType;
FreeDosObject(DOS_FIB, fib);
UnLock(lock);
return TRUE;
}
return FALSE;
}
///
/// FileSize
// Returns size of a file
int FileSize(char *filename)
{
int size;
if (FileInfo(filename, &size, NULL, NULL)) return size; else return -1;
}
///
/// FileProtection
// Returns protection bits of a file
long FileProtection(char *filename)
{
long bits;
if (FileInfo(filename, NULL, &bits, NULL)) return bits; else return -1;
}
///
/// FileType
// Returns file type (file/directory)
int FileType(char *filename)
{
long type;
if (FileInfo(filename, NULL, NULL, &type)) return (type < 0 ? 1 : 2); else return 0;
}
///
/// FileExists
// Checks if a file exists
BOOL FileExists(char *filename)
{
return FileInfo(filename, NULL, NULL, NULL);
}
///
/// RenameFile
// Renames a file and restores the protection bits
BOOL RenameFile(char *oldname, char *newname)
{
struct FileInfoBlock *fib;
BPTR lock;
if (!Rename(oldname, newname)) return FALSE;
if((fib = AllocDosObject(DOS_FIB,NULL)))
{
if ((lock = Lock(newname, ACCESS_READ)))
{
Examine(lock, fib); UnLock(lock);
SetProtection(newname, fib->fib_Protection & (~FIBF_ARCHIVE));
}
FreeDosObject(DOS_FIB,fib);
} else return FALSE;
return TRUE;
}
///
/// CopyFile
// Copies a file
BOOL CopyFile(char *dest, FILE *destfh, char *sour, FILE *sourfh)
{
BOOL success = FALSE;
if (sour) sourfh = fopen(sour, "r");
if (dest) destfh = fopen(dest, "w");
if (sourfh && destfh)
{
char buf[SIZE_LARGE];
int len;
success = TRUE;
while ((len = fread(buf, 1, SIZE_LARGE, sourfh)))
if (fwrite(buf, 1, len, destfh) != len) { success = FALSE; break; }
}
if (dest && destfh) fclose(destfh);
if (sour && sourfh) fclose(sourfh);
return success;
}
///
/// ConvertCRLF
// Converts line breaks from LF to CRLF or vice versa
BOOL ConvertCRLF(char *in, char *out, BOOL to)
{
BOOL success = FALSE;
char buf[SIZE_LINE];
FILE *infh, *outfh;
if ((infh = fopen(in, "r")))
{
if ((outfh = fopen(out, "w")))
{
while (GetLine(infh, buf, SIZE_LINE)) fprintf(outfh, "%s%s\n", buf, to?"\r":"");
success = TRUE;
fclose(outfh);
}
fclose(infh);
}
return success;
}
///
/// GetWord
// Word-wrapping algorithm: gets next word
LOCAL int GetWord(char **rptr, char *wbuf, int max)
{
int c, i = 0;
static int nonblanks = 0;
if (!(c = *(*rptr)++)) { *wbuf = 0; return 0; }
if (isSpace(c))
{
while (isSpace(c) && c != '\n')
{
if (i < max-1) wbuf[i++] = c;
c = *(*rptr)++;
}
if (c == '\n' || !c) { i = 0; wbuf[i++] = '\n'; }
}
else
{
while (isGraph(c))
{
if (i < max-1) wbuf[i++] = c; else break;
c = *(*rptr)++;
}
nonblanks += i;
while (isSpace(c) && c != '\n') c = *(*rptr)++;
if (c == '\n')
{
if (nonblanks <= 20) wbuf[i++] = '\n';
nonblanks = 0;
}
}
if (isGraph(c)) (*rptr)--;
wbuf[i] = '\0'; return i;
}
///
/// ReflowParagraph
// Word-wrapping algorithm: process a paragraph
LOCAL char *ReflowParagraph(char *start, char *end, int lmax, char *dest)
{
int lword, lline = 0;
char c, word[SIZE_LARGE], *p;
BOOL dented = FALSE;
while ((lword = GetWord(&start, word, SIZE_LARGE)))
{
if ((c = word[lword-1]) == '\n') word[--lword] = '\0';
if (!lword);
else if (isSpace(*word))
{
if (lline) *dest++ = '\n';
dented = TRUE; lline = lword;
for (p = word; *p; p++) *dest++ = *p;
}
else
{
if (lline == 0 || dented) { for (p = word; *p; p++) *dest++ = *p; lline += lword; dented = FALSE; }
else
{
if (lline+lword < lmax) { *dest++ = ' '; for (p = word; *p; p++) *dest++ = *p; lline += lword+1; }
else { *dest++ = '\n'; for (p = word; *p; p++) *dest++ = *p; lline = lword; }
}
}
if (c == '\n') { *dest++ = '\n'; lline = 0; }
if (start > end) break;
}
if (lline) *dest++ = '\n';
*dest-- = 0;
return dest;
}
///
/// RemoveQuoteString
// Removes reply prefix
LOCAL char *RemoveQuoteString(char *start, char *end, char *quot, char *dest)
{
while (start <= end)
{
if (!strncmp(start, quot, strlen(quot))) start += strlen(quot);
while (*start && *start != '\n') *dest++ = *start++;
if (*start) *dest++ = *start++;
}
*dest-- = 0;
return dest;
}
///
/// InsertQuoteString
// Inserts reply prefix
LOCAL char *InsertQuoteString(char *start, char *quote, FILE *out)
{
if ((*start != '\n' || C->QuoteEmptyLines) && strncmp(start, "<sb>", 4) && strncmp(start, "<tsb>", 5))
{
int level, i;
for (i = level = 0; start[i] && start[i] != '\n' && i < 16; i++)
{
if (isSpace(start[i]) && (!level || start[i+1] == '>')) continue;
if (start[i] == '>') level++; else if (!isAlNum(start[i]) || level) break;
}
if (level) start = &start[i];
if (level > 8) level = 8;
fputs(quote, out); while (level--) fputc('>', out);
if (*start != ' ') fputc(' ', out);
}
return start;
}
///
/// SaveParagraph
// Writes a paragraph and inserts reply prefixes
LOCAL void SaveParagraph(char *start, char *end, char *prefix, FILE *out)
{
while (start <= end)
{
if (*prefix) start = InsertQuoteString(start, prefix, out);
while (*start && *start != '\n') fputc(*start++, out);
if (*start) fputc(*start++, out);
}
}
///
/// QuoteWordWrap
// Reformats quoted messages to a new line length
void QuoteWordWrap(char *rptr, int lmax, char *prefix, char *firstprefix, FILE *out)
{
if (!prefix) prefix = firstprefix;
while (*rptr)
{
char *p, *ps = rptr, *pe, quot[17], c;
int lsm = 0;
*quot = 0;
while (TRUE)
{
int ls = 0;
char *p = rptr;
while (*rptr && *rptr != '\n') { rptr++; ls++; }
if (ls && *p == '>' && !*quot)
{
int i = 0;
while ((*p == ' ' || *p == '>') && i < 16) quot[i++] = *p++;
quot[i] = 0;
while (i > 1) if (quot[i-2] == ' ' && quot[i-1] == ' ') quot[--i] = 0; else break;
}
if (ls > lsm) lsm = ls;
if (!*rptr) break;
c = rptr[1];
if (isSpace(c) || !c || c == '\n') break;
if (!*quot && c == '>') break;
if (*quot) if (strncmp(&rptr[1], quot, strlen(quot))) break;
rptr++;
}
pe = rptr;
if (lsm > lmax)
{
if (*quot)
{
char *buf = calloc(2*(pe-ps+2),1), newprefix[SIZE_DEFAULT];
RemoveQuoteString(ps, pe, quot, buf);
strcpy(newprefix, firstprefix); strcat(newprefix, TrimEnd(quot));
QuoteWordWrap(buf, lmax-strlen(quot), newprefix, firstprefix, out);
free(buf);
}
else
{
char *buf = calloc(2*(pe-ps+2),1);
p = ReflowParagraph(ps, pe, lmax, buf);
SaveParagraph(buf, p, prefix, out);
free(buf);
}
}
else SaveParagraph(ps, pe, prefix, out);
rptr = pe+1;
}
}
///
/// SimpleWordWrap
// Reformats a file to a new line length
void SimpleWordWrap(char *filename, int wrapsize)
{
BPTR fh;
if ((fh = Open((STRPTR)filename, MODE_OLDFILE)))
{
char ch;
int p = 0, lsp = -1, sol = 0;
while (Read(fh, &ch, 1))
{
if (p-sol > wrapsize && lsp >= 0)
{
ch = '\n';
Seek(fh, lsp-p-1, OFFSET_CURRENT);
p = lsp;
Write(fh, &ch, 1);
}
if (ISpace(ch)) lsp = p;
if (ch == '\n') { sol = p+1; lsp = -1; }
p++;
}
Close(fh);
}
}
///
/// ReqFile
// Puts up a file requester
int ReqFile(int num, struct Object *win, char *title, int mode, char *drawer, char *file)
{
static BOOL init[MAXASL] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE };
static char *pattern[MAXASL] = { "#?.addressbook#?", "#?.config#?", NULL, NULL, "#?.(yam|rexx)", "#?.(gif|jpg|jpeg|png|iff|ilbm)", NULL, NULL };
struct Window *truewin;
int skip = *file ? 1 : 2;
char *postext = (mode & 1)==1 ? GetStr(MSG_UT_Save) : GetStr(MSG_UT_Load);
get(win, MUIA_Window_Window, &truewin);
if (!init[num]) { init[num] = TRUE; skip = 0; }
return MUI_AslRequestTags(G->ASLReq[num],
ASLFR_Window, truewin,
ASLFR_TitleText, title,
ASLFR_PositiveText, postext,
ASLFR_InitialFile, file,
ASLFR_DoSaveMode, (mode & 1)==1,
ASLFR_DoMultiSelect, (mode & 2)==2,
ASLFR_DrawersOnly, (mode & 4)==4,
ASLFR_DoPatterns, pattern[num] != NULL,
skip ? TAG_DONE : ASLFR_InitialDrawer, drawer,
ASLFR_InitialPattern, pattern[num] ? pattern[num] : "#?",
TAG_DONE);
}
///
/// OpenTempFile
// Creates or opens a temporary file
struct TempFile *OpenTempFile(char *mode)
{
static int count = 0;
struct TempFile *tf;
if ((tf = calloc(1, sizeof(struct TempFile))))
{
char buf[SIZE_SMALL];
sprintf(buf, "YAM.%ld.tmp", ++count);
strmfp(tf->Filename, C->TempDir, buf);
if (!mode) return tf;
if ((tf->FP = fopen(tf->Filename, mode))) return tf;
free(tf);
}
return NULL;
}
///
/// CloseTempFile
// Closes a temporary file
void CloseTempFile(struct TempFile *tf)
{
if (tf)
{
if (tf->FP) fclose(tf->FP);
DeleteFile(tf->Filename);
free(tf);
}
}
///
/// DumpClipboard
// Exports contents of clipboard unit 0 to a file
#define ID_FTXT MAKE_ID('F','T','X','T')
#define ID_CHRS MAKE_ID('C','H','R','S')
BOOL DumpClipboard(FILE *out)
{
struct IFFHandle *iff;
struct ContextNode *cn;
long error, rlen;
UBYTE readbuf[SIZE_DEFAULT];
BOOL success = FALSE;
if ((iff = AllocIFF()))
{
if ((iff->iff_Stream = (ULONG)OpenClipboard(PRIMARY_CLIP)))
{
InitIFFasClip(iff);
if (!OpenIFF(iff, IFFF_READ))
{
if (!StopChunk(iff, ID_FTXT, ID_CHRS)) while (TRUE)
{
error = ParseIFF(iff, IFFPARSE_SCAN);
if (error == IFFERR_EOC) continue; else if (error) break;
cn = CurrentChunk(iff);
if (cn) if (cn->cn_Type == ID_FTXT && cn->cn_ID == ID_CHRS)
{
success = TRUE;
while ((rlen = ReadChunkBytes(iff, readbuf, SIZE_DEFAULT)) > 0)
fwrite(readbuf, 1, rlen, out);
}
}
CloseIFF(iff);
}
CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
}
FreeIFF(iff);
}
return success;
}
///
/// IsFolderDir
// Checks if a directory is used as a mail folder
BOOL IsFolderDir(char *dir)
{
char *filename = FilePart(dir);
int i;
for (i = 0; i < 4; i++) if (!stricmp(filename, FolderNames[i])) return TRUE;
return (BOOL)(PFExists(dir, ".fconfig") || PFExists(dir, ".index"));
}
///
/// PFExists
// Checks if a file exists in the specified directory
BOOL PFExists(char *path, char *file)
{
char fname[SIZE_PATHFILE];
strmfp(fname, path, file);
return (BOOL)(FileSize(fname) >= 0);
}
///
/// DeleteMailDir
// Recursively deletes a mail directory
void DeleteMailDir(char *dir, BOOL isroot)
{
BOOL cont, isdir;
struct FileInfoBlock *fib;
BPTR lock;
char fname[SIZE_PATHFILE], *filename, dirname[SIZE_PATHFILE];
fib = AllocDosObject(DOS_FIB,NULL);
if ((lock = Lock(dir, ACCESS_READ)))
{
strcpy(dirname, dir);
Examine(lock, fib);
cont = (ExNext(lock,fib) && IoErr() != ERROR_NO_MORE_ENTRIES);
while (cont)
{
strmfp(fname, dir, fib->fib_FileName);
filename = FilePart(fname);
isdir = fib->fib_DirEntryType > 0;
cont = (ExNext(lock,fib) && IoErr() != ERROR_NO_MORE_ENTRIES);
if (isroot)
{
if (isdir)
{
if (IsFolderDir(fname)) DeleteMailDir(fname, FALSE);
}
else
{
if (!stricmp(filename, ".config") || !stricmp(filename, ".glossary") || !stricmp(filename, ".addressbook")) DeleteFile(fname);
}
}
else if (!isdir) if (!stricmp(filename, ".fconfig") || !stricmp(filename, ".index") || IsValidMailFile(filename)) DeleteFile(fname);
}
UnLock(lock);
DeleteFile(dirname);
}
FreeDosObject(DOS_FIB,fib);
}
///
/// FileToBuffer
// Reads a complete file into memory
LOCAL char *FileToBuffer(char *file)
{
char *text;
int size = FileSize(file);
FILE *fh;
if (size >= 0) if ((text = calloc(size+1,1)))
{
if ((fh = fopen(file, "r")))
{
fread(text, 1, size, fh);
fclose(fh);
return text;
}
free(text);
}
return NULL;
}
///
/*** Mail related ***/
/// MyAddTail
// Adds a message to a message list
void MyAddTail(struct Mail **list, struct Mail *new)
{
struct Mail *mail;
new->Next = NULL;
if (!*list) { *list = new; return; }
for (mail = *list; mail->Next; mail = mail->Next);
mail->Next = new;
}
///
/// MyRemove
// Removes a message from a message list
void MyRemove(struct Mail **list, struct Mail *rem)
{
struct Mail *mail;
if (*list == rem) { *list = rem->Next; return; }
for (mail = *list; mail->Next; mail = mail->Next)
if (mail->Next == rem) { mail->Next = rem->Next; return; }
}
///
/// WhichLV
// Returns pointer to message listview if folder is active
APTR WhichLV(struct Folder *folder)
{
if (folder == FO_GetCurrentFolder()) return G->MA->GUI.NL_MAILS; else return NULL;
}
///
/// CreateFilename
// Prepends mail directory to a file name
char *CreateFilename(char *file)
{
static char buffer[SIZE_PATHFILE];
strmfp(buffer, G->MA_MailDir, file);
return buffer;
}
///
/// CreateDirectory
// Makes a directory
BOOL CreateDirectory(char *dir)
{
int t = FileType(dir);
if (t == 2) return TRUE;
if (t == 0)
{
BPTR fl = CreateDir((STRPTR)dir);
if (fl)
{
UnLock(fl);
return TRUE;
}
}
if (G->MA) ER_NewError(GetStr(MSG_ER_CantCreateDir), dir, NULL);
return FALSE;
}
///
/// GetFolderDir
// Returns path of a folder directory
char *GetFolderDir(struct Folder *fo)
{
static char buffer[SIZE_PATH];
if (strchr(fo->Path, ':')) return fo->Path;
strmfp(buffer, G->MA_MailDir, fo->Path);
return buffer;
}
///
/// GetMailFile
// Returns path of a message file
char *GetMailFile(char *string, struct Folder *folder, struct Mail *mail)
{
static char buffer[SIZE_PATHFILE];
if (!folder && mail) folder = mail->Folder;
if (!string) string = buffer;
strmfp(string, (int)folder <= 0 ? C->TempDir : GetFolderDir(folder), mail->MailFile);
return string;
}
///
/// GetMailInfo
// Returns location of a message
struct MailInfo *GetMailInfo(struct Mail *smail)
{
static struct MailInfo mi;
int i;
mi.Display = smail->Folder == FO_GetCurrentFolder();
mi.Pos = -1;
mi.FName = GetMailFile(NULL, smail->Folder, smail);
if (mi.Display) for (i=0; mi.Pos == -1; i++)
{
struct Mail *mail;
DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_GetEntry, i, &mail);
if (!mail) break;
if (mail == smail) mi.Pos = i;
}
return &mi;
}
///
/// GetReturnAddress
// Gets return address of a message
struct Person *GetReturnAddress(struct Mail *mail)
{
if (mail->ReplyTo.Address[0]) return &mail->ReplyTo;
return &mail->From;
}
///
/// BuildAddrName
// Creates "Real Name" <E-mail> string
char *BuildAddrName(char *address, char *name)
{
static char buffer[SIZE_ADDRESS+SIZE_REALNAME+4];
char *delim;
if (*name)
{
if (strpbrk(name, ",.()")) delim = "\""; else delim = "";
sprintf(buffer, "%s%s%s <%s>", delim, name, delim, address);
}
else sprintf(buffer, "%s", address);
return buffer;
}
char *BuildAddrName2(struct Person *pe)
{
return BuildAddrName(pe->Address, pe->RealName);
}
///
/// ExtractAddress
// Extracts e-mail address and real name
void ExtractAddress(char *line, struct Person *pe)
{
char *p = line, *ra[4], *save = malloc(strlen(line)+1);
BOOL found = FALSE;
ra[2] = ra[3] = NULL;
strcpy(save, line);
pe->Address[0] = pe->RealName[0] = 0;
while (ISpace(*p)) p++;
if ((ra[0] = MyStrChr(p,'<'))) if ((ra[1] = MyStrChr(ra[0],'>')))
{
*ra[0]++ = 0; *ra[1] = 0;
for (ra[2] = p, ra[3] = ra[0]-2; ISpace(*ra[3]) && ra[3] >= ra[2]; ra[3]--) *ra[3] = 0;
found = TRUE;
}
if (!found)
{
for (ra[1] = ra[0] = p; *ra[1] && *ra[1] != '\t' && *ra[1] != ' ' && *ra[1] != ','; ra[1]++);
if ((ra[2] = MyStrChr(ra[1],'('))) if ((ra[3] = MyStrChr(ra[2],')')))
{
ra[2]++; *ra[3]-- = 0;
found = TRUE;
}
*ra[1] = 0;
if (!found) ra[2] = ra[3] = "";
}
if (*ra[2] == '\"') ra[2]++;
if (*ra[3] == '\"' && *(ra[3]-1) != '\\') *ra[3] = 0;
stccpy(pe->Address , Trim(ra[0]), SIZE_ADDRESS);
stccpy(pe->RealName, Trim(ra[2]), SIZE_REALNAME);
strcpy(line, save);
free(save);
}
///
/// CompressMsgID
// Creates a compressed version of the message ID
int CompressMsgID(char *msgid)
{
int i = 0, compr = 0;
char *ptr = msgid;
while (*ptr) compr += ++i*123*(*ptr++);
return compr;
}
///
/// ExpandText
// Replaces variables with values
char *ExpandText(char *src, struct ExpandTextData *etd)
{
static char chr[2] = { 0,0 };
char buf[SIZE_ADDRESS], *p, *p2, *dst = AllocStrBuf(SIZE_DEFAULT);
struct DateStamp adate;
for (; *src; src++)
if (*src == '\\')
{
src++;
switch (*src)
{
case '\\': dst = StrBufCat(dst, "\\"); break;
case 'n': dst = StrBufCat(dst, "\n"); break;
}
}
else if (*src == '%' && etd)
{
if (!etd->OM_Date) etd->OM_Date = DateStamp(&adate);
src++;
switch (*src)
{
case 'n': dst = StrBufCat(dst, etd->OS_Name); break;
case 'f': stccpy(buf, etd->OS_Name, SIZE_ADDRESS);
if ((p = strchr(buf, ','))) p = Trim(++p);
else { for (p = buf; *p && *p != ' '; p++); *p = 0; p = buf; }
dst = StrBufCat(dst, p); break;
case 's': dst = StrBufCat(dst, etd->OM_Subject); break;
case 'e': dst = StrBufCat(dst, etd->OS_Address); break;
case 'd': dst = StrBufCat(dst, DateStamp2String(etd->OM_Date, DSS_DATE)); break;
case 't': dst = StrBufCat(dst, DateStamp2String(etd->OM_Date, DSS_TIME)); break;
case 'w': dst = StrBufCat(dst, DateStamp2String(etd->OM_Date, DSS_WEEKDAY)); break;
case 'm': dst = StrBufCat(dst, etd->OM_MessageID); break;
case 'r': dst = StrBufCat(dst, etd->R_Name); break;
case 'v': strcpy(buf, etd->R_Name);
if ((p = strchr(buf, ','))) p = Trim(++p);
else { for (p = buf; *p && *p != ' '; p++); *p = 0; p = buf; }
dst = StrBufCat(dst, p); break;
case 'a': dst = StrBufCat(dst, etd->R_Address); break;
case 'i': strcpy(buf, etd->OS_Name);
for (p = p2 = &buf[1]; *p; p++)
if (*p == ' ' && p[1] && p[1] != ' ') *p2++ = *++p;
*p2 = 0;
dst = StrBufCat(dst, buf); break;
case 'j': strcpy(buf, etd->OS_Name);
for (p2 = &buf[1], p = &buf[strlen(buf)-1]; p > p2; p--)
if (p[-1] == ' ') { *p2++ = *p; break; }
*p2 = 0;
dst = StrBufCat(dst, buf); break;
case 'h': if ((p = FileToBuffer(etd->HeaderFile)))
{
dst = StrBufCat(dst, p); free(p);
}
break;
}
}
else
{
chr[0] = *src;
dst = StrBufCat(dst, chr);
}
return dst;
}
///
/// DescribeCT
// Returns description of a content type
char *DescribeCT(char *ct)
{
int i;
for (i = 0; i < MAXCTYPE; i++)
if (!stricmp(ct, ContType[i])) { ct = GetStr(ContTypeDesc[i]); break; }
return ct;
}
///
/// GetDateStamp
// Get number of seconds since 1/1-1978
time_t GetDateStamp(void)
{
struct DateStamp ds;
struct DateStamp *rds;
rds = DateStamp(&ds);
return (rds->ds_Days*24*60*60 + rds->ds_Minute*60 + rds->ds_Tick/TICKS_PER_SECOND);
}
///
/// DateStamp2String
// Converts a datestamp to a string
char *DateStamp2String(struct DateStamp *date, int mode)
{
static char resstr[32];
char *s, datestr[16], timestr[16], daystr[16];
struct DateTime dt;
struct DateStamp dsnow;
long beat;
// if this argument is not set we get the actual time
if (!date) date = DateStamp(&dsnow);
clear(&dt, sizeof(struct DateTime));
dt.dat_Stamp = *date;
dt.dat_Format = FORMAT_DOS;
if (mode == DSS_USDATETIME || mode == DSS_UNIXDATE) dt.dat_Format = FORMAT_USA;
dt.dat_StrDate = (STRPTR)datestr;
dt.dat_StrTime = (STRPTR)timestr;
dt.dat_StrDay = (STRPTR)daystr;
DateToStr(&dt);
// strip spaces a.s.o.
s = Trim(datestr);
switch (mode)
{
case DSS_UNIXDATE:
{
int y = atoi(&s[6]);
// this is a Y2K patch
// if less then 8035 days has passed since 1.1.1978 then we are in the 20th century
if (date->ds_Days < 8035) y += 1900;
else y += 2000;
sprintf(resstr, "%s %s %02ld %s %ld\n", wdays[dt.dat_Stamp.ds_Days%7], months[atoi(s)-1], atoi(&s[3]), timestr, y);
}
break;
case DSS_DATETIME:
{
timestr[5] = 0;
sprintf(resstr, "%s %s", s, timestr);
}
break;
case DSS_DATEBEAT:
{
// calculate the beat time
beat = (((date->ds_Minute-60*C->TimeZone+(C->DaylightSaving?0:60)+1440)%1440)*1000)/1440;
sprintf(resstr, "%s @%03ld", s, beat);
}
break;
case DSS_USDATETIME:
{
sprintf(resstr, "%s %s", s, timestr);
}
break;
case DSS_WEEKDAY:
{
strcpy(resstr, daystr);
}
break;
case DSS_DATE:
{
strcpy(resstr, s);
}
break;
case DSS_TIME:
{
strcpy(resstr, timestr);
}
break;
case DSS_BEAT:
{
// calculate the beat time
beat = (((date->ds_Minute-60*C->TimeZone+(C->DaylightSaving?0:60)+1440)%1440)*1000)/1440;
sprintf(resstr, "@%03ld", beat);
}
break;
}
return resstr;
}
///
/// DateStamp2Long
// Converts a datestamp to a numeric value
long DateStamp2Long(struct DateStamp *date)
{
char *s, datestr[16];
struct DateStamp dsnow;
struct DateTime dt;
int y;
if (!date) date = DateStamp(&dsnow);
clear(&dt, sizeof(struct DateTime));
dt.dat_Stamp = *date;
dt.dat_Format = FORMAT_USA;
dt.dat_StrDate = (STRPTR)datestr;
DateToStr(&dt); s = Trim(datestr);
// get the year
y = atoi(&s[6]);
// this is a Y2K patch
// if less then 8035 days has passed since 1.1.1978 then we are in the 20th century
if (date->ds_Days < 8035) y += 1900;
else y += 2000;
return((100*atoi(&s[3])+atoi(s))*10000+y);
}
///
/// GetTZ
// Gets the locale time zone
char *GetTZ(void)
{
static char tzone[SIZE_SMALL];
if (GetVar("YAM_TZ", tzone, SIZE_SMALL, 0) < 0)
{
int tz, tzd;
if (G->Locale) {
CloseLocale(G->Locale);
G->Locale = OpenLocale(NULL);
tz = -G->Locale->loc_GMTOffset/60;
}
else tz = C->TimeZone;
tzd = tz + (C->DaylightSaving ? 1 : 0);
if (tz >= 0) sprintf(tzone, "+%02d00", tzd);
else sprintf(tzone, "-%02d00", -tzd);
}
return tzone;
}
///
/// TZtoMinutes
// Converts time zone into a numeric offset
LOCAL int TZtoMinutes(char *tzone)
{
int i, tzcorr = 0;
static struct TimeZones { char *TZname; int TZcorr; }
tzones[] = { "sst",-1100, "pst",-800, "mst",-700, "pdt",-700, "cst",-600,
"mdt",-600, "est",-500, "ast",-500, "edt",-400, "wgt",-300, "wgst",-200,
"aat",-100, "egt",-100, "egst",0, "gmt",0, "utc",0, "wat",0, "wet",0,
"bst",100, "cat",100, "cet",100, "met",100, "west",100, "cest",200,
"met dst",200, "eet",200, "ist",200, "sat",200, "ast",300, "eat",300,
"eest",300, "idt",300, "msk",300, "adt",400, "msd",300, "gst",400,
"smt",400, "ict",400, "hkt",800, "wst",800, "jst",900, "kst",1000,
"nzst",1200, "nzdt",1300, NULL,0 };
if (tzone[0] == '+') tzcorr = atoi(&tzone[1]);
else if (tzone[0] == '-') tzcorr = -atoi(&tzone[1]);
else for (i = 0; tzones[i].TZname; i++)
if (!strnicmp(tzones[i].TZname, tzone, strlen(tzones[i].TZname)))
{ tzcorr = tzones[i].TZcorr; break; }
tzcorr = (tzcorr/100)*60 + (tzcorr%100);
return tzcorr;
}
///
/// ScanDate
// Converts textual date header into datestamp format
struct DateStamp *ScanDate(char *date)
{
int count = 0, day = 0, mon = 0, year = 0, hour = 0, min = 0, sec = 0;
char *tzone = "", *p, tdate[SIZE_SMALL], ttime[SIZE_SMALL];
static struct DateTime dt;
struct DateStamp *ds = &dt.dat_Stamp;
if ((p = strchr(date, ','))) p++; else p = date;
while (*p && ISpace(*p)) p++;
while ((p = strtok(p, " \t")))
{
switch (count)
{
case 0: if (!isdigit(*p)) return NULL;
if ((day = atoi(p)) > 31) return NULL;
break;
case 1: for (mon = 1; mon <= 12; mon++) if (!strnicmp(p, months[mon-1], 3)) break;
if (mon > 12) return NULL;
break;
case 2: year = atoi(p);
break;
case 3: if (sscanf(p, "%d:%d:%d", &hour, &min, &sec) == 3) ;
else if (sscanf (p, "%d:%d", &hour, &min) == 2) sec = 0;
else return NULL;
break;
case 4: while (*p && (ISpace(*p) || *p == '(')) p++;
tzone = p;
break;
}
count++; p = NULL;
}
sprintf(tdate, "%02ld-%02ld-%02ld", mon, day, year%100);
sprintf(ttime, "%02ld:%02ld:%02ld", hour, min, sec);
dt.dat_Format = FORMAT_USA;
dt.dat_Flags = 0;
dt.dat_StrDate = (STRPTR)tdate;
dt.dat_StrTime = (STRPTR)ttime;
StrToDate(&dt);
ds->ds_Minute -= TZtoMinutes(tzone);
ds->ds_Minute += TZtoMinutes(GetTZ());
while (ds->ds_Minute < 0) { ds->ds_Minute += 1440; ds->ds_Days--; }
while (ds->ds_Minute >= 1440) { ds->ds_Minute -= 1440; ds->ds_Days++; }
return ds;
}
///
/// FormatSize
// Displays large numbers using group separators
void FormatSize(int size, char *buffer)
{
char *gs = G->Locale ? (char *)G->Locale->loc_GroupSeparator : ".";
char *p = &buffer[strlen(buffer)];
if (size >= 1000000) sprintf(p, "%d%s%03d%s%03d", size/1000000, gs, (size%1000000)/1000, gs, size%1000);
if (size >= 1000 && size < 1000000) sprintf(p, "%d%s%03d", size/1000, gs, size%1000);
if (size < 1000) sprintf(p, "%d", size);
}
///
/// MailExists
// Checks if a message still exists
BOOL MailExists(struct Mail *mailptr, struct Folder *folder)
{
struct Mail *work;
if (Virtual(mailptr)) return TRUE;
if (!folder) folder = mailptr->Folder;
for (work = folder->Messages; work; work = work->Next) if (work == mailptr) return TRUE;
return FALSE;
}
///
/// SelectMessage
// Activates a message in the message listview
int SelectMessage(struct Mail *mail)
{
struct MailInfo *mi;
if (mail->Folder != FO_GetCurrentFolder()) MA_ChangeFolder(mail->Folder);
mi = GetMailInfo(mail);
if (mi->Pos >= 0) set(G->MA->GUI.NL_MAILS, MUIA_NList_Active, mi->Pos);
return mi->Pos;
}
///
/// DisplayMailList
// Lists folder contents in the message listview
void DisplayMailList(struct Folder *fo, APTR lv)
{
struct Mail *work, **array;
if ((array = (struct Mail **)calloc(fo->Total+1,sizeof(struct Mail *))))
{
int i = 0;
Busy(GetStr(MSG_BusyDisplayingList), "", 0, 0);
for (work = fo->Messages; work; work = work->Next) array[i++] = work;
set(lv, MUIA_NList_Quiet, TRUE);
DoMethod(lv, MUIM_NList_Clear);
DoMethod(lv, MUIM_NList_Insert, array, fo->Total, MUIV_NList_Insert_Sorted);
set(lv, MUIA_NList_Quiet, FALSE);
free(array);
BusyEnd;
}
}
///
/// AddMailToList
// Adds a message to a folder
struct Mail *AddMailToList(struct Mail *mail, struct Folder *folder)
{
struct Mail *new = malloc(sizeof(struct Mail));
if (new)
{
*new = *mail;
new->Folder = folder;
MyAddTail(&(folder->Messages), new);
folder->Total++;
folder->Size += mail->Size;
if (mail->Status == STATUS_NEW) { folder->New++; folder->Unread++; }
if (mail->Status == STATUS_UNR) folder->Unread++;
MA_ExpireIndex(folder);
}
return new;
}
///
/// RemoveMailFromList
// Removes a message from a folder
void RemoveMailFromList(struct Mail *mail)
{
struct Folder *folder = mail->Folder;
folder->Total--;
folder->Size -= mail->Size;
if (mail->Status == STATUS_NEW) { folder->New--; folder->Unread--; }
if (mail->Status == STATUS_UNR) folder->Unread--;
MA_ExpireIndex(folder);
MyRemove(&(folder->Messages), mail);
free(mail);
}
///
/// ClearMailList
// Removes all messages from a folder
void ClearMailList(struct Folder *folder, BOOL resetstats)
{
struct Mail *work, *next;
for (work = folder->Messages; work; work = next)
{
next = work->Next;
free(work);
}
if (resetstats) folder->Total = folder->New = folder->Unread = folder->Size = 0;
folder->Messages = NULL;
}
///
/// GetPackMethod
// Returns packer type and efficiency
LOCAL BOOL GetPackMethod(int xpktype, char **method, int *eff)
{
if (xpktype == 2) { *method = C->XPKPack; *eff = C->XPKPackEff; return TRUE; }
if (xpktype == 3) { *method = C->XPKPackEncrypt; *eff = C->XPKPackEncryptEff; return TRUE; }
return FALSE;
}
///
/// CompressMailFile
// Shrinks a message file
LOCAL BOOL CompressMailFile(char *src, char *dst, char *passwd, char *method, int eff)
{
int err;
if (!XpkBase) return FALSE;
err = XpkPackTags(XPK_InName, src, XPK_OutName, dst, XPK_Password, passwd, XPK_PackMethod, method, XPK_PackMode, eff, TAG_DONE);
return (BOOL)!err;
}
///
/// UncompressMailFile
// Expands a compressed message file
LOCAL BOOL UncompressMailFile(char *src, char *dst, char *passwd)
{
if (!XpkBase) return FALSE;
return (BOOL)(!XpkUnpackTags(XPK_InName, src, XPK_OutName, dst, XPK_Password, passwd, TAG_DONE));
}
///
/// TransferMailFile
// Copies or moves a message file, handles compression
BOOL TransferMailFile(BOOL copyit, struct Mail *mail, struct Folder *dstfolder)
{
char *pmeth, srcbuf[SIZE_PATHFILE], dstbuf[SIZE_PATHFILE];
struct Folder *srcfolder = mail->Folder;
int peff = 0;
int srcxpk = srcfolder->XPKType, dstxpk = dstfolder->XPKType;
char *srcpw = srcfolder->Password, *dstpw = dstfolder->Password;
BOOL one2one, needuncomp, needcomp, done = FALSE, success = FALSE;
if (!MA_GetIndex(srcfolder)) return FALSE;
if (!MA_GetIndex(dstfolder)) return FALSE;
one2one = (srcxpk == dstxpk) && (srcxpk != 3);
needuncomp = srcxpk > 1;
needcomp = dstxpk > 1;
GetPackMethod(dstxpk, &pmeth, &peff);
GetMailFile(srcbuf, srcfolder, mail);
strcpy(dstbuf, MA_NewMailFile(dstfolder, mail->MailFile, atoi(mail->MailFile)));
if (one2one && !copyit) if ((done = RenameFile(srcbuf, dstbuf))) success = TRUE;
if (!done)
{
if (needuncomp)
if (needcomp)
if (one2one)
success = CopyFile(dstbuf, 0, srcbuf, 0);
else
{
struct TempFile *tf = OpenTempFile(NULL);
if (UncompressMailFile(srcbuf, tf->Filename, srcpw))
success = CompressMailFile(tf->Filename, dstbuf, dstpw, pmeth, peff);
CloseTempFile(tf);
}
else
success = UncompressMailFile(srcbuf, dstbuf, srcpw);
else
if (needcomp)
success = CompressMailFile(srcbuf, dstbuf, dstpw, pmeth, peff);
else
success = CopyFile(dstbuf, 0, srcbuf, 0);
if (success && !copyit) DeleteFile(srcbuf);
if (success) SetComment(dstbuf, Status[mail->Status]);
}
return success;
}
///
/// RepackMailFile
// (Re/Un)Compresses a message file
BOOL RepackMailFile(struct Mail *mail, int dstxpk, char *passwd)
{
char *pmeth = NULL, srcbuf[SIZE_PATHFILE], dstbuf[SIZE_PATHFILE];
struct Folder *folder = mail->Folder;
int peff = 0, srcxpk = folder->XPKType;
BOOL success = TRUE;
MA_GetIndex(folder);
GetMailFile(srcbuf, folder, mail);
GetPackMethod(dstxpk, &pmeth, &peff);
sprintf(dstbuf, "%s.tmp", srcbuf);
switch (4*srcxpk+dstxpk)
{
case 0: case 5: case 10: case 15:
case 1: case 4: return TRUE;
case 2: case 3: case 6: case 7: if ((success = CompressMailFile(srcbuf, dstbuf, passwd, pmeth, peff)))
{
DeleteFile(srcbuf);
success = RenameFile(dstbuf, srcbuf);
}
break;
case 8: case 9: case 12: case 13: if ((success = UncompressMailFile(srcbuf, dstbuf, folder->Password)))
{
DeleteFile(srcbuf);
success = RenameFile(dstbuf, srcbuf);
}
break;
case 11: case 14: if ((success = UncompressMailFile(srcbuf, dstbuf, folder->Password)))
{
success = CompressMailFile(dstbuf, srcbuf, passwd, pmeth, peff);
DeleteFile(dstbuf);
}
break;
}
MA_SetMailStatus(mail, mail->Status);
return success;
}
///
/// DoPack
// Compresses a file
BOOL DoPack(char *file, char *newfile, struct Folder *folder)
{
char *pmeth = NULL;
int peff = 0;
GetPackMethod(folder->XPKType, &pmeth, &peff);
if (!CompressMailFile(file, newfile, folder->Password, pmeth, peff)) return FALSE;
DeleteFile(file);
return TRUE;
}
///
/// StartUnpack
// Unpacks a file to a temporary file
char *StartUnpack(char *file, char *newfile, struct Folder *folder)
{
FILE *fh;
BOOL xpk = FALSE;
if ((fh = fopen(file, "r")))
{
if (fgetc(fh) == 'X') if (fgetc(fh) == 'P') if (fgetc(fh) == 'K') xpk = TRUE;
fclose(fh);
if (xpk)
{
char nfile[SIZE_FILE];
stcgfn(nfile, file); sprintf(&nfile[strlen(nfile)], "_%08lx.unp", folder);
strmfp(newfile, C->TempDir, nfile);
if (FileSize(newfile) < 0) if (!UncompressMailFile(file, newfile, folder ? folder->Password : "")) return NULL;
}
else strcpy(newfile, file);
return newfile;
}
return NULL;
}
///
/// FinishUnpack
// Deletes temporary unpacked file
void FinishUnpack(char *file)
{
if (strstr(file, ".unp")) DeleteFile(file);
}
///
/// IsValidMailFile
// Checks if a message file name is valid
BOOL IsValidMailFile(char *fname)
{
int l = strlen(fname);
if (l < 7 || l > 10 || fname[5] != '.') return FALSE;
while (--l >= 0) if (l != 5 && !isdigit(fname[l])) return FALSE;
return TRUE;
}
///
/*** Editor related ***/
/// EditorToFile
// Saves contents of a texteditor object to a file
BOOL EditorToFile(struct Object *editor, char *file, struct TranslationTable *tt)
{
char *text;
UBYTE *p;
FILE *fh;
if (!(fh = fopen(file, "w"))) return FALSE;
text = (char *)DoMethod((Object *)editor, MUIM_TextEditor_ExportText);
if (tt) for (p = text; *p; ++p) *p = tt->Table[*p];
fputs(text, fh);
fclose(fh);
FreeVec(text);
return TRUE;
}
///
/// FileToEditor
// Loads a file into a texteditor object
BOOL FileToEditor(char *file, struct Object *editor)
{
char *text = FileToBuffer(file);
if (!text) return FALSE;
set(editor, MUIA_TextEditor_Contents, text);
free(text);
return TRUE;
}
///
/*** Hooks ***/
/// GeneralDesFunc
// General purpose destruction hook
long SAVEDS ASM GeneralDesFunc(REG(a1,void *entry))
{
free(entry);
return 0;
}
MakeHook(GeneralDesHook, GeneralDesFunc);
///
/// PO_SetPublicKey
// Copies public PGP key from list to string gadget
void SAVEDS ASM PO_SetPublicKey(REG(a1,APTR string), REG(a2,APTR pop))
{
char *var, buf[SIZE_SMALL];
DoMethod(pop, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &var);
if (var)
{
strcpy(buf, "0x");
strncat(buf, var, 8);
setstring(string, buf);
}
}
MakeHook(PO_SetPublicKeyHook, PO_SetPublicKey);
///
/// PO_ListPublicKeys
// Lists keys of public PGP keyring in a popup window
long SAVEDS ASM PO_ListPublicKeys(REG(a1,APTR string), REG(a2,APTR pop))
{
BOOL secret;
char buf[SIZE_LARGE], *str, p;
int retc, keys = 0;
FILE *fp;
get(pop, MUIA_UserData, &str); secret = (BOOL)(str != NULL); // MUIA_UserData is actually BOOL already, but 32bit!
if (G->PGPVersion == 5)
retc = PGPCommand("pgpk", "-l +language=us", KEEPLOG);
else
{
strcpy(buf, "-kv ");
if (secret)
{
GetVar("PGPPATH", &buf[4], SIZE_DEFAULT, 0);
if ((p = buf[strlen(buf)-1]) != ':' && p != '/') strcat(buf, "/");
strcat(buf, "secring.pgp");
}
retc = PGPCommand("pgp", buf, KEEPLOG);
}
if (!retc) if ((fp = fopen(PGPLOGFILE, "r")))
{
get(string, MUIA_String_Contents, &str);
DoMethod(pop, MUIM_List_Clear);
while (GetLine(fp, buf, sizeof(buf)))
{
char entry[SIZE_DEFAULT];
clear(entry, SIZE_DEFAULT);
if (G->PGPVersion == 5)
{
if (!strncmp(buf, "sec", 3) || (!strncmp(&buf[1], "ub", 2) && !secret))
{
memcpy(entry, &buf[12], 8);
while (GetLine(fp, buf, sizeof(buf)))
if (!strncmp(buf, "uid", 3)) { strncat(entry, &buf[4], SIZE_DEFAULT-9); break; }
}
}
else
{
if (buf[9] == '/' && buf[23] == '/')
{
memcpy(entry, &buf[10], 8);
strncat(entry, &buf[29], SIZE_DEFAULT-8);
}
}
if (*entry)
{
DoMethod(pop, MUIM_List_InsertSingle, entry, MUIV_List_Insert_Bottom);
if (!strncmp(entry, str, 8)) set(pop, MUIA_List_Active, keys);
keys++;
}
}
fclose(fp);
DeleteFile(PGPLOGFILE);
}
if (!keys) ER_NewError(GetStr(MSG_ER_NoPublicKeys), "", "");
return keys > 0;
}
MakeHook(PO_ListPublicKeysHook, PO_ListPublicKeys);
///
/*** MUI related ***/
/// ShortCut
// Finds keyboard shortcut in text label
char ShortCut(char *label)
{
char *ptr = strchr(label, '_');
if (!ptr) return 0;
return (char)ToLower(*++ptr);
}
/*********** Function isn't used anywhere! -msbethke **************
///
/// RemoveCut
// Removes shortcut character from text label
LOCAL char *RemoveCut(char *label)
{
static char lab[SIZE_DEFAULT], *p;
for (p = lab; *label; label++) if (*label != '_') *p++ = *label;
*p = 0;
return lab;
}
*/
///
/// SetHelp
// Sets bubble help of a MUI object
void SetHelp(APTR object, APTR strnum)
{
set(object, MUIA_ShortHelp, GetStr(strnum));
}
///
/// MakeCycle
// Creates a MUI cycle object
Object *MakeCycle(char **labels, char *label)
{
Object *obj = KeyCycle(labels, ShortCut(label));
if (obj) set(obj, MUIA_CycleChain, 1);
return obj;
}
///
/// MakeButton
// Creates a MUI button
Object *MakeButton(char *txt)
{
Object *obj = MUI_MakeObject(MUIO_Button,txt);
if (obj) set(obj, MUIA_CycleChain, 1);
return obj;
}
///
/// MakeCheck
// Creates a MUI checkmark object
Object *MakeCheck(char *label)
{
return
ImageObject,
ImageButtonFrame,
MUIA_InputMode , MUIV_InputMode_Toggle,
MUIA_Image_Spec , MUII_CheckMark,
MUIA_Background , MUII_ButtonBack,
MUIA_ShowSelState, FALSE,
MUIA_ControlChar , ShortCut(label),
MUIA_CycleChain , 1,
End;
}
///
/// MakeCheckGroup
// Creates a labelled MUI checkmark object
Object *MakeCheckGroup(Object **check, char *label)
{
return
HGroup,
Child, *check = MakeCheck(label),
Child, Label1(label),
Child, HSpace(0),
End;
}
///
/// MakeString
// Creates a MUI string object
Object *MakeString(int maxlen, char *label)
{
return BetterStringObject,
StringFrame,
MUIA_String_MaxLen , maxlen,
MUIA_String_AdvanceOnCR, TRUE,
MUIA_ControlChar , ShortCut(label),
MUIA_CycleChain , 1,
End;
}
///
/// MakePassString
// Creates a MUI string object with hidden text
Object *MakePassString(char *label)
{
return BetterStringObject,
StringFrame,
MUIA_String_MaxLen , SIZE_PASSWORD,
MUIA_String_Secret , TRUE,
MUIA_String_AdvanceOnCR, TRUE,
MUIA_ControlChar , ShortCut(label),
MUIA_CycleChain , 1,
End;
}
///
/// MakeInteger
// Creates a MUI string object for numeric input
Object *MakeInteger(int maxlen, char *label)
{
Object *str = MakeString(maxlen, label);
if (str)
{
set(str, MUIA_String_Integer, 0);
set(str, MUIA_String_Accept, "0123456789");
}
return str;
}
///
/// MakePGPKeyList
// Creates a PGP id popup list
Object *MakePGPKeyList(APTR *st, BOOL secret, char *label)
{
APTR po, lv;
if ((po = PopobjectObject,
MUIA_Popstring_String, *st = MakeString(SIZE_DEFAULT, label),
MUIA_Popstring_Button, PopButton(MUII_PopUp),
MUIA_Popobject_StrObjHook, &PO_ListPublicKeysHook,
MUIA_Popobject_ObjStrHook, &PO_SetPublicKeyHook,
MUIA_Popobject_WindowHook, &PO_WindowHook,
MUIA_Popobject_Object, lv = ListviewObject,
MUIA_UserData, secret,
MUIA_Listview_List, ListObject,
InputListFrame,
MUIA_List_AdjustWidth, TRUE,
MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
MUIA_List_DestructHook, MUIV_List_DestructHook_String,
End,
End,
End))
DoMethod(lv, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, po, 2, MUIM_Popstring_Close, TRUE);
return po;
}
///
/// MakePicture
// Creates a MUI image object that uses image datatypes
Object *MakePicture(char *fname)
{
return G->DtpicSupported ?
MUI_NewObject("Dtpic.mui", MUIA_Dtpic_Name, fname, End :
NewObject(CL_BodyChunk->mcc_Class,NULL, MUIA_Bodychunk_File, fname, End;
}
///
/// MakeStatusFlag
// Creates a MUI object for status images
Object *MakeStatusFlag(char *fname)
{
return NewObject(CL_BodyChunk->mcc_Class,NULL,
MUIA_Bodychunk_File, fname,
MUIA_Bodychunk_UseOld, TRUE,
MUIA_Bitmap_Transparent, 0,
End;
}
///
/// MakeNumeric
// Creates a MUI numeric slider
Object *MakeNumeric(int min, int max, BOOL percent)
{
return
NumericbuttonObject,
MUIA_Numeric_Min, min,
MUIA_Numeric_Max, max,
MUIA_Numeric_Format, percent ? "%ld%%" : "%ld",
MUIA_CycleChain, 1,
End;
}
///
/// MakeMenuitem
// Creates a menu item from a catalog string
Object *MakeMenuitem(const UBYTE *str, ULONG ud)
{
if (str == NULL) return (MenuitemObject, MUIA_Menuitem_Title, NM_BARLABEL, End);
if (str[1] == '\0')
return (MenuitemObject,
MUIA_Menuitem_Title, str+2,
MUIA_Menuitem_Shortcut, str,
MUIA_UserData, ud,
End);
else
return (MenuitemObject,
MUIA_Menuitem_Title, str,
MUIA_UserData, ud,
End);
}
///
/// SetupToolbar
// Initializes a single button in a MUI toolbar object
void SetupToolbar(struct MUIP_Toolbar_Description *tb, char *label, char *help, UWORD flags)
{
tb->Type = label ? (*label ? TDT_BUTTON : TDT_SPACE) : TDT_END;
tb->Flags = flags;
tb->ToolText = tb->Type == TDT_BUTTON ? label : NULL;
tb->HelpString = help;
tb->MutualExclude = 0; tb->Key = 0;
}
///
/// SetupMenu
// Initializes a MUI menu item
void SetupMenu(int type, struct NewMenu *menu, char *label, char *shortcut, int id)
{
menu->nm_Type = type;
menu->nm_Label = (STRPTR)label;
menu->nm_CommKey = (STRPTR)shortcut;
menu->nm_Flags = 0;
menu->nm_MutualExclude = 0;
menu->nm_UserData = (APTR)id;
}
///
/// DoSuperNew
// Calls parent NEW method within a subclass
#ifdef __MORPHOS__
ULONG DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...)
{
ULONG tags[4 * 2];
va_list args;
// SVR4 varargs to Tags hack.
va_start(args, tag1);
tags[0] = tag1;
memcpy(tags + 1, args->reg_save_area + 3 * 4, 5 * 4);
tags[6] = TAG_MORE;
tags[7] = (ULONG)args->overflow_arg_area;
va_end(args);
return DoSuperMethod(cl, obj, OM_NEW, tags, NULL);
}
#else
ULONG DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...)
{
return DoSuperMethod(cl, obj, OM_NEW, &tag1, NULL);
}
#endif
///
/// GetMUI
// Gets an attribute value from a MUI object
int GetMUI(struct Object *obj,int attr)
{
LONG b;
get(obj,attr,&b);
return (int)b;
}
///
/// GetMUIStringPtr
// Returns a pointer to the value of a MUI string object
char *GetMUIStringPtr(struct Object *obj)
{
return (char*)GetMUI(obj,MUIA_String_Contents);
}
///
/// GetMUIString
// Returns the value of a MUI string object
void GetMUIString(char *a,struct Object *obj)
{
strcpy(a,(char*)GetMUI(obj,MUIA_String_Contents));
}
///
/// GetMUIText
// Returns the value of a MUI text object
void GetMUIText(char *a,struct Object *obj)
{
strcpy(a,(char*)GetMUI(obj,MUIA_Text_Contents));
}
///
/// GetMUIInteger
// Returns the numeric value of a MUI string object
int GetMUIInteger(struct Object *obj)
{
return GetMUI(obj,MUIA_String_Integer);
}
///
/// GetMUICheck
// Returns the value of a MUI checkmark object
BOOL GetMUICheck(struct Object *obj)
{
return (BOOL)GetMUI(obj, MUIA_Selected);
}
///
/// GetMUICycle
// Returns the value of a MUI cycle object
int GetMUICycle(struct Object *obj)
{
return GetMUI(obj, MUIA_Cycle_Active);
}
///
/// GetMUIRadio
// Returns the value of a MUI radio object
int GetMUIRadio(struct Object *obj)
{
return GetMUI(obj, MUIA_Radio_Active);
}
///
/// GetMUINumer
// Returns the value of a MUI numeric slider
int GetMUINumer(struct Object *obj)
{
return GetMUI(obj, MUIA_Numeric_Value);
}
///
/// SafeOpenWindow
// Tries to open a window
BOOL SafeOpenWindow(struct Object *obj)
{
int isopen, isicon;
set(obj, MUIA_Window_Open, TRUE);
get(obj, MUIA_Window_Open, &isopen);
get(_app(obj), MUIA_Application_Iconified, &isicon);
if (isopen || isicon) return TRUE;
DisplayBeep(0);
return FALSE;
}
///
/// DisposeModule
// Frees resources of a MUI window
void DisposeModulePush(void *module)
{
DoMethod(G->App, MUIM_Application_PushMethod, G->App, 3, MUIM_CallHook, &DisposeModuleHook, module);
}
void DisposeModule(void *modptr)
{
struct UniversalClassData **module = (struct UniversalClassData **)modptr;
if (*module)
{
APTR window = (*module)->GUI.WI;
set(window, MUIA_Window_Open, FALSE);
DoMethod(G->App, OM_REMMEMBER, window);
#ifndef __SASC
if(modptr!=&G->WR[0] && modptr!=&G->WR[1] && modptr!=&G->WR[2])
#endif
MUI_DisposeObject(window);
free(*module);
*module = NULL;
}
}
void SAVEDS ASM DisposeModuleFunc(REG(a1,void **arg))
{
DisposeModule(arg[0]);
}
MakeHook(DisposeModuleHook,DisposeModuleFunc);
///
/// LoadLayout
// Loads column widths from ENV:MUI/YAM.cfg
void LoadLayout(void)
{
char *ls;
DoMethod(G->App, MUIM_Application_Load, MUIV_Application_Load_ENV);
if (!*(ls = GetMUIStringPtr(G->MA->GUI.ST_LAYOUT))) ls = "35 100 25 100 30 100";
sscanf(ls, "%ld %ld %ld %ld %ld %ld", &G->Weights[0], &G->Weights[1], &G->Weights[2], &G->Weights[3], &G->Weights[4], &G->Weights[5]);
}
///
/// SaveLayout
// Saves column widths to ENV(ARC):MUI/YAM.cfg
void SaveLayout(BOOL permanent)
{
char buf[SIZE_DEFAULT];
sprintf(buf, "%ld %ld %ld %ld %ld %ld", G->Weights[0], G->Weights[1], G->Weights[2], G->Weights[3], G->Weights[4], G->Weights[5]);
setstring(G->MA->GUI.ST_LAYOUT, buf);
DoMethod(G->App, MUIM_Application_Save, MUIV_Application_Save_ENV);
if (permanent) DoMethod(G->App, MUIM_Application_Save, MUIV_Application_Save_ENVARC);
}
///
/// ConvertKey
// Converts input event to key code
ULONG ConvertKey(struct IntuiMessage *imsg)
{
struct InputEvent event;
UBYTE code = 0;
event.ie_NextEvent = NULL;
event.ie_Class = IECLASS_RAWKEY;
event.ie_SubClass = 0;
event.ie_Code = imsg->Code;
event.ie_Qualifier = imsg->Qualifier;
event.ie_EventAddress = (APTR *) *((ULONG *)imsg->IAddress);
MapRawKey(&event, &code, 1, NULL);
return code;
}
///
/**** BodyChunk ****/
/// FreeBCImage
// Frees a bodychunk image
void FreeBCImage(struct BodyChunkData *bcd)
{
if (bcd)
{
if (bcd->Colors) free(bcd->Colors);
if (bcd->Body) free(bcd->Body);
free(bcd);
}
}
///
/// GetBCImage
// Searches for a bodychunk image by filename
struct BodyChunkData *GetBCImage(char *fname)
{
int i;
for (i = 0; i < MAXIMAGES; i++)
if (G->BImage[i]) if (!strcmp(G->BImage[i]->File, fname)) return G->BImage[i];
return NULL;
}
///
/// LoadBCImage
// Loads a bodychunk image from disk
struct BodyChunkData *LoadBCImage(char *fname)
{
struct IFFHandle *iff;
struct ContextNode *cn;
struct BodyChunkData *bcd;
if ((bcd = calloc(1,sizeof(struct BodyChunkData))))
{
if ((iff = AllocIFF()))
{
if ((iff->iff_Stream = Open(fname, MODE_OLDFILE)))
{
InitIFFasDOS(iff);
if (!OpenIFF(iff, IFFF_READ))
{
if (!ParseIFF(iff, IFFPARSE_STEP))
{
if ((cn=CurrentChunk(iff)) && (cn->cn_ID == ID_FORM))
{
if (cn->cn_Type == ID_ILBM)
{
struct StoredProperty *sp;
struct BitMapHeader *bmhd;
int i, size;
if (!PropChunk (iff, ID_ILBM, ID_BMHD) &&
!PropChunk (iff, ID_ILBM, ID_CMAP) &&
!StopChunk (iff, ID_ILBM, ID_BODY) &&
!StopOnExit(iff, ID_ILBM, ID_FORM) &&
!ParseIFF (iff, IFFPARSE_SCAN))
{
if ((sp = FindProp(iff, ID_ILBM, ID_CMAP)))
{
bcd->Colors = calloc(sp->sp_Size,sizeof(ULONG));
for (i = 0; i < sp->sp_Size; i++)
{
UBYTE c = ((UBYTE *)sp->sp_Data)[i];
bcd->Colors[i] = (c<<24)|(c<<16)|(c<<8)|c;
}
}
if ((sp = FindProp(iff,ID_ILBM,ID_BMHD)))
{
bmhd = (struct BitMapHeader *)sp->sp_Data;
if (bmhd->bmh_Compression == cmpNone || bmhd->bmh_Compression==cmpByteRun1)
{
size = CurrentChunk(iff)->cn_Size;
if ((bcd->Body = calloc(size,1)))
{
if (ReadChunkBytes(iff, bcd->Body, size) == size)
{
bcd->Width = bmhd->bmh_Width;
bcd->Height = bmhd->bmh_Height;
bcd->Depth = bmhd->bmh_Depth;
bcd->Compression = bmhd->bmh_Compression;
bcd->Masking = bmhd->bmh_Masking;
stcgfn(bcd->File, fname);
}
}
}
}
}
}
}
}
}
CloseIFF(iff);
}
Close(iff->iff_Stream);
}
FreeIFF(iff);
}
else return NULL;
if (!bcd->Depth) { FreeBCImage(bcd); return NULL; }
return bcd;
}
///
/*** Miscellaneous stuff ***/
/// PGPGetPassPhrase
// Asks user for the PGP passphrase
void PGPGetPassPhrase(void)
{
if (!G->PGPPassPhrase[0])
{
G->PGPPassVolatile = FALSE;
if (GetVar("PGPPASS", G->PGPPassPhrase, SIZE_DEFAULT, 0) < 0)
{
char pgppass[SIZE_DEFAULT];
G->PGPPassVolatile = TRUE; *pgppass = 0;
if (StringRequest(pgppass, SIZE_DEFAULT, "PGP", GetStr(MSG_UT_PGPPassReq), GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), TRUE, G->MA->GUI.WI))
strcpy(G->PGPPassPhrase, pgppass);
}
else return;
}
SetVar("PGPPASS", G->PGPPassPhrase, -1, GVF_GLOBAL_ONLY);
}
///
/// PGPClearPassPhrase
// Clears the ENV variable containing the PGP passphrase
void PGPClearPassPhrase(BOOL force)
{
if (G->PGPPassVolatile) DeleteVar("PGPPASS", 0);
if (force) G->PGPPassPhrase[0] = 0;
}
///
/// PGPCommand
// Launches a PGP command
int PGPCommand(char *progname, char *options, int flags)
{
BPTR fhi,fho;
int error = -1;
char command[SIZE_LARGE];
if ((fhi = Open("NIL:", MODE_OLDFILE)))
{
if ((fho = Open("NIL:", MODE_NEWFILE)))
{
Busy(GetStr(MSG_BusyPGPrunning), "", 0, 0);
strmfp(command, C->PGPCmdPath, progname);
strcat(command, " >" PGPLOGFILE " ");
strcat(command, options);
error = SystemTags(command, SYS_Input, fhi, SYS_Output, fho, NP_StackSize, C->StackSize, TAG_DONE);
Close(fho);
BusyEnd;
}
Close(fhi);
}
if (error > 0 && !(flags & NOERRORS)) ER_NewError(GetStr(MSG_ER_PGPreturnsError), command, PGPLOGFILE);
if (error < 0) ER_NewError(GetStr(MSG_ER_PGPnotfound), C->PGPCmdPath, NULL);
if (!error && !(flags & KEEPLOG)) DeleteFile(PGPLOGFILE);
return error;
}
///
/// AppendToLogfile
// Appends a line to the logfile
LOCAL void AppendToLogfile(int id, char *text, void *a1, void *a2, void *a3, void *a4)
{
FILE *fh;
char logfile[SIZE_PATHFILE], filename[SIZE_FILE];
if (!C->LogAllEvents && (id < 30 || id > 49)) return;
if (C->SplitLogfile)
{
struct ClockData cd;
Amiga2Date(GetDateStamp(), &cd);
sprintf(filename, "YAM-%s%ld.log", months[cd.month-1], cd.year);
}
else strcpy(filename, "YAM.log");
strmfp(logfile, *C->LogfilePath ? C->LogfilePath : G->ProgDir, filename);
if ((fh = fopen(logfile, "a")))
{
fprintf(fh, "%s [%02ld] ", DateStamp2String(NULL, DSS_DATETIME), id);
fprintf(fh, text, a1, a2, a3, a4);
fprintf(fh, "\n");
fclose(fh);
}
}
///
/// AppendLog
// Appends a line to the logfile, depending on log mode
void AppendLog(int id, char *text, void *a1, void *a2, void *a3, void *a4)
{
if (C->LogfileMode != 0) AppendToLogfile(id, text, a1, a2, a3, a4);
}
void AppendLogNormal(int id, char *text, void *a1, void *a2, void *a3, void *a4)
{
if (C->LogfileMode == 1) AppendToLogfile(id, text, a1, a2, a3, a4);
}
void AppendLogVerbose(int id, char *text, void *a1, void *a2, void *a3, void *a4)
{
if (C->LogfileMode == 2) AppendToLogfile(id, text, a1, a2, a3, a4);
}
///
/// Busy
// Displays busy message and sleep pointer
int BusyLevel = 0;
void Busy(char *text, char *parameter, int cur, int max)
{
static char infotext[SIZE_DEFAULT];
if (text)
{
if (*text)
{
sprintf(infotext, text, parameter);
if (G->MA && !BusyLevel)
{
set(G->MA->GUI.GA_INFO, MUIA_Gauge_InfoText, infotext);
set(G->MA->GUI.GA_INFO, MUIA_Gauge_Max, max);
}
BusyLevel++;
set(G->App, MUIA_Application_Sleep, TRUE);
}
else
{
set(G->App, MUIA_Application_Sleep, FALSE);
if (BusyLevel) --BusyLevel;
if (G->MA && !BusyLevel)
{
set(G->MA->GUI.GA_INFO, MUIA_Gauge_InfoText, "");
set(G->MA->GUI.GA_INFO, MUIA_Gauge_Current, 0);
}
}
}
else
{
set(G->MA->GUI.GA_INFO, MUIA_Gauge_Current, cur);
}
}
///
/// DisplayStatistics
// Calculates folder statistics and update mailbox status icon
void DisplayStatistics(struct Folder *fo)
{
struct Mail *mail;
BOOL check = FALSE;
struct Folder *actfo = FO_GetCurrentFolder();
static char apptit[SIZE_DEFAULT/2];
// If the parsed argument is NULL we set want to show the statistics from the actual folder
if (!fo) fo = actfo;
if (fo == (struct Folder *)-1)
{
fo = FO_GetFolderByType(FT_INCOMING, NULL);
check = TRUE;
}
for (mail = fo->Messages, fo->Unread = fo->New = 0; mail; mail = mail->Next)
{
if (mail->Status == STATUS_NEW) { fo->New++; fo->Unread++; }
if (mail->Status == STATUS_UNR) fo->Unread++;
}
DoMethod(G->MA->GUI.NL_FOLDERS, MUIM_NList_Redraw, FO_GetFolderPosition(fo), TAG_DONE);
if (fo == actfo)
{
MA_SetMessageInfoFunc();
MA_SetFolderInfoFunc();
}
// if the folder that statistic has changed is the incoming folder we also have to change the AppIcon accordingly
if (fo->Type == FT_INCOMING && !G->AppIconQuiet)
{
if (check || fo->New != G->NewMsgs || fo->Unread != G->UnrMsgs || fo->Total != G->TotMsgs)
{
// we set the mode accordingly to the status of the folder (new/check/old)
int mode = fo->Total ? (fo->New ? 2 : 1) : 0;
if (G->TR && G->TR->Checking) mode = 3;
SPrintF(apptit, GetStr(MSG_APPICON_STATS), fo->New, fo->Unread, fo->Total);
// We first have to remove the appicon before we can change it
if (G->AppIcon)
{
RemoveAppIcon(G->AppIcon);
G->AppIcon = NULL;
}
// Now we create the new AppIcon and display it
if (G->DiskObj[mode])
{
struct DiskObject *dobj=G->DiskObj[mode];
G->AppIcon = AddAppIconA(0, 0, (STRPTR)apptit, G->AppPort, NULL, dobj, NULL);
}
G->NewMsgs = fo->New;
G->UnrMsgs = fo->Unread;
G->TotMsgs = fo->Total;
}
}
}
///
/// CheckPrinter
// Checks if printer is ready
BOOL CheckPrinter(void)
{
struct MsgPort *PrintPort;
struct IOStdReq *PrintIO;
UWORD Result = 0;
char _PrinterDeviceName[] = "printer.device";
long _PrinterDeviceUnit = 0;
char *error = NULL;
if ((PrintPort = CreateMsgPort()))
{
PrintPort->mp_Node.ln_Name = "YAM PrintPort";
if ((PrintIO = CreateIORequest(PrintPort, sizeof(struct IOStdReq))))
{
if (!(OpenDevice((STRPTR)_PrinterDeviceName, _PrinterDeviceUnit, (struct IORequest *)PrintIO, 0)))
{
PrintIO->io_Message.mn_ReplyPort = PrintPort;
PrintIO->io_Command = PRD_QUERY;
PrintIO->io_Data = &Result;
DoIO((struct IORequest *)PrintIO);
if(PrintIO->io_Actual == 1) // parallel port printer?
{
if (((Result>>8) & 3) == 0) error = NULL; // no error
else if ((Result>>8) & 01) error = GetStr(MSG_UT_NoPaper); // /POUT asserted
else error = GetStr(MSG_UT_NoPrinter); // /BUSY (hopefully no RingIndicator interference)
} else error = NULL; // can't determine status of serial printers
CloseDevice((struct IORequest *)PrintIO);
}
DeleteIORequest((struct IORequest *)PrintIO);
}
DeleteMsgPort(PrintPort);
}
if (error) if (!MUI_Request(G->App, NULL, 0, GetStr(MSG_ErrorReq), GetStr(MSG_OkayCancelReq), error)) return False;
return True;
}
///
/// PlaySound
// Plays a sound file using datatypes
void PlaySound(char *filename)
{
if (DataTypesBase)
{
struct dtTrigger Play = { DTM_TRIGGER, NULL, STM_PLAY, NULL };
Object *sound;
BYTE sig;
if ((sound = NewDTObject((APTR)filename, DTA_GroupID, GID_SOUND, SDTA_Volume, 64, SDTA_Cycles, 1, TAG_DONE)))
{
if ((sig = AllocSignal(-1)) >= 0)
{
if (SetDTAttrs(sound, NULL, NULL, SDTA_SignalTask, FindTask(NULL), SDTA_SignalBit, 1<<sig, TAG_END) == 2)
{
DoDTMethodA(sound, NULL, NULL, (Msg)&Play);
Wait(1<<sig);
}
else
{
ULONG length = 0, period = 394, cycles = 1, frequency, seconds;
GetDTAttrs(sound, SDTA_SampleLength, &length, SDTA_Period, &period, SDTA_Cycles, &cycles, TAG_END);
if (length > 131072) length = 131072;
frequency = (ULONG)(SysBase->ex_EClockFrequency * 5) / period;
seconds = (length * cycles) / frequency + 1;
DoDTMethodA(sound, NULL, NULL, (Msg)&Play);
Delay(seconds * 50);
}
FreeSignal(sig);
}
DisposeDTObject(sound);
}
}
}
///
/// MatchExtension
// Matches a file extension against a list of extension
BOOL MatchExtension(char *fileext, char *extlist)
{
while ((extlist = strtok(extlist, " ")))
{
if (!stricmp(extlist, fileext)) return TRUE;
extlist = NULL;
}
return FALSE;
}
///
/// IdentifyFileDT
// Detects the file type using datatypes.library
LOCAL char *IdentifyFileDT(char *fname)
{
static char ctype[SIZE_CTYPE], *type = NULL;
struct Library *DataTypesBase = OpenLibrary("datatypes.library", 39);
strcpy(ctype, "application/octet-stream");
if (DataTypesBase)
{
BPTR lock;
if ((lock = Lock(fname, ACCESS_READ)))
{
struct DataType *dtn;
if ((dtn = ObtainDataTypeA(DTST_FILE, (APTR)lock, NULL)))
{
struct DataTypeHeader *dth = dtn->dtn_Header;
switch (dth->dth_GroupID)
{
case GID_SYSTEM: break;
case GID_DOCUMENT: type = "application"; break;
case GID_TEXT: type = "text"; break;
case GID_SOUND:
case GID_INSTRUMENT: type = "audio"; break;
case GID_PICTURE: type = "image"; break;
case GID_MOVIE:
case GID_ANIMATION: type = "video"; break;
}
if (type) sprintf(ctype, "%s/x-%s", type, dth->dth_BaseName);
ReleaseDataType(dtn);
}
UnLock (lock);
}
CloseLibrary(DataTypesBase);
}
return ctype;
}
///
/// IdentifyFile
// Detects the file type by analyzing file extension and contents
char *IdentifyFile(char *fname)
{
char *ctype = "";
long bits = FileProtection(fname);
FILE *fh;
if ((fh = fopen(fname, "r")))
{
int i, len;
char buffer[SIZE_LARGE], *ext;
len = fread(buffer, 1, SIZE_LARGE-1, fh);
buffer[len] = 0;
fclose(fh);
if ((ext = strrchr(fname, '.'))) ++ext; else ext = "--";
if (!stricmp(ext, "htm") || !stricmp(ext, "html"))
ctype = ContType[CT_TX_HTML];
else if (!strnicmp(buffer, "@database", 9) || !stricmp(ext, "guide"))
ctype = ContType[CT_TX_GUIDE];
else if (!stricmp(ext, "ps") || !stricmp(ext, "eps"))
ctype = ContType[CT_AP_PS];
else if (!stricmp(ext, "rtf"))
ctype = ContType[CT_AP_RTF];
else if (!stricmp(ext, "lha") || !strncmp(&buffer[2], "-lh5-", 5))
ctype = ContType[CT_AP_LHA];
else if (!stricmp(ext, "lzx") || !strncmp(buffer, "LZX", 3))
ctype = ContType[CT_AP_LZX];
else if (!stricmp(ext, "zip"))
ctype = ContType[CT_AP_ZIP];
else if (*((long *)buffer) >= HUNK_UNIT && *((long *)buffer) <= HUNK_INDEX)
ctype = ContType[CT_AP_AEXE];
else if (!stricmp(ext, "rexx") || !stricmp(ext+strlen(ext)-2, "rx"))
ctype = ContType[CT_AP_REXX];
else if (!strncmp(&buffer[6], "JFIF", 4))
ctype = ContType[CT_IM_JPG];
else if (!strncmp(buffer, "GIF8", 4))
ctype = ContType[CT_IM_GIF];
else if (!strnicmp(ext, "png",4) || !strncmp(&buffer[1], "PNG", 3))
ctype = ContType[CT_IM_PNG];
else if (!strnicmp(ext, "tif",4))
ctype = ContType[CT_IM_TIFF];
else if (!strncmp(buffer, "FORM", 4) && !strncmp(&buffer[8], "ILBM", 4))
ctype = ContType[CT_IM_ILBM];
else if (!stricmp(ext, "au") || !stricmp(ext, "snd"))
ctype = ContType[CT_AU_AU];
else if (!strncmp(buffer, "FORM", 4) && !strncmp(&buffer[8], "8SVX", 4))
ctype = ContType[CT_AU_8SVX];
else if (!stricmp(ext, "wav"))
ctype = ContType[CT_AU_WAV];
else if (!stricmp(ext, "mpg") || !stricmp(ext, "mpeg"))
ctype = ContType[CT_VI_MPG];
else if (!stricmp(ext, "qt") || !stricmp(ext, "mov"))
ctype = ContType[CT_VI_MOV];
else if (!strncmp(buffer, "FORM", 4) && !strncmp(&buffer[8], "ANIM", 4))
ctype = ContType[CT_VI_ANIM];
else if (!stricmp(ext, "avi"))
ctype = ContType[CT_VI_AVI];
else if (stristr(buffer, "\nFrom:"))
ctype = ContType[CT_ME_EMAIL];
else
{
for (i = 1; i < MAXMV; i++) if (C->MV[i])
if (MatchExtension(ext, C->MV[i]->Extension)) ctype = C->MV[i]->ContentType;
}
if (!*ctype)
{
int notascii = 0;
for (i = 0; i < len; i++)
if ((int)buffer[i] < 32 || (int)buffer[i] > 127)
if (buffer[i] != '\t' && buffer[i] != '\n') notascii++;
if (notascii < len/10) ctype = ContType[(bits&FIBF_SCRIPT) ? CT_AP_SCRIPT : CT_TX_PLAIN];
else ctype = IdentifyFileDT(fname);
}
}
return ctype;
}
///
/// LoadTranslationTable
// Load a translation table into memory
BOOL LoadTranslationTable(struct TranslationTable **tt, char *file)
{
FILE *fp;
if (*tt) free(*tt);
if (!*file) return FALSE;
if (!(*tt = calloc(1,sizeof(struct TranslationTable)))) return FALSE;
if ((fp = fopen(file, "r")))
{
UBYTE buf[SIZE_DEFAULT], *p;
int i;
for (i = 0; i < 256; i++) (*tt)->Table[i] = (UBYTE)i;
stccpy((*tt)->File, file, SIZE_PATHFILE);
fgets(buf, SIZE_DEFAULT, fp);
if (!strncmp(buf, "YCT1", 4))
{
fgets((*tt)->Name, SIZE_DEFAULT, fp);
if ((p = strchr((*tt)->Name,'\n'))) *p = 0;
while (fgets(buf, SIZE_DEFAULT, fp))
if (!strnicmp(buf, "from", 4)) stccpy((*tt)->SourceCharset, Trim(&buf[5]), SIZE_CTYPE);
else if (!strnicmp(buf, "to", 2)) stccpy((*tt)->DestCharset, Trim(&buf[3]), SIZE_CTYPE);
else if (!strnicmp(buf, "header", 6)) (*tt)->Header = TRUE;
else if (!strnicmp(buf, "author", 6));
else if (strchr(buf, '='))
{
int source, dest;
p = buf;
if (*p == '$') stch_i(&p[1], &source); else source = (int)*p;
while (*p++ != '=');
if (*p == '$') stch_i(&p[1], &dest); else dest = (int)*p;
if (source >= 0 && source <= 0xFF && dest >= 0 && dest <= 0xFF) (*tt)->Table[source] = (UBYTE)dest;
}
fclose(fp);
return TRUE;
}
fclose(fp);
}
ER_NewError(GetStr(MSG_ER_ErrorTTable), file, NULL);
free(*tt); *tt = NULL;
return FALSE;
}
///
/// ExecuteCommand
// Executes a DOS command
BOOL ExecuteCommand(char *cmd, BOOL asynch, BPTR outdef)
{
BPTR in, out, path;
int ret;
switch (outdef)
{
case NULL: in = Input();out = Output(); break;
case OUT_NIL: out = Open("NIL:", MODE_NEWFILE); in = Open("NIL:", MODE_OLDFILE); break;
default: out = outdef; in = Open("NIL:", MODE_OLDFILE); break;
}
if (!outdef) asynch = FALSE;
if (_WBenchMsg)
{
path = CloneWorkbenchPath(_WBenchMsg);
if ((ret = SystemTags(cmd, SYS_Input,in, SYS_Output,out, NP_Path,path, NP_StackSize,C->StackSize, SYS_Asynch,asynch, TAG_DONE)) == -1) FreeWorkbenchPath(path);
}
else ret = SystemTags(cmd, SYS_Input,in, SYS_Output,out, NP_StackSize,C->StackSize, SYS_Asynch,asynch, TAG_DONE);
if (ret == -1 && asynch && outdef) { Close(out); Close(in); }
return (BOOL)(!ret);
}
///
/// GetSimpleID
// Returns a unique number
int GetSimpleID(void)
{
static int num = 0;
return ++num;
}
///
/// GotoURL
// Loads an URL using an ARexx script or openurl.library
void GotoURL(char *url)
{
if (C->RX[MACRO_URL].Script[0])
{
char newurl[SIZE_LARGE];
sprintf(newurl, "%c%s%c", '"', url, '"');
MA_StartMacro(MACRO_URL, newurl);
}
else if ((OpenURLBase = OpenLibrary("openurl.library", 1)))
{
URL_Open(url, TAG_DONE);
CloseLibrary(OpenURLBase);
}
}
///
/// strtok_r()
// Reentrant version of stdlib strtok()
// Call like this:
// char *next=input, *token, breakstring[]=", ";
// do { token = strtok_r(&next,breakstring); /* ... */ } while(next);
char *strtok_r(char **s, char *brk)
{
char *p,*ret;
if((s == NULL) || (*s == NULL) || (brk == NULL))
return NULL;
/* find break character */
if((p = strpbrk(*s,brk)))
{
/* if found, terminate string there */
*p = '\0';
/* scan forward to next non-break */
do { p++; } while(*p && (strchr(brk,*p) != NULL));
/* if *p is a nullbyte, then no more tokens */
if(*p == '\0') p = NULL;
/* save current *s to return it */
ret = *s;
/* and let *s point to first non-break */
*s = p;
return ret;
}
/* no break character found - *s gets NULL */
ret = *s;
*s = NULL;
return ret;
}
///
/*** REXX interface support ***/
/// InsertAddresses
// Appends an array of addresses to a string gadget
void InsertAddresses(APTR obj, char **addr, BOOL add)
{
char *buf;
get(obj, MUIA_String_Contents, &buf);
if (*buf && add) DoMethod(obj, MUIM_BetterString_Insert, ", ", MUIV_BetterString_Insert_EndOfString);
else setstring(obj, "");
DoMethod(obj, MUIM_BetterString_Insert, *addr, MUIV_BetterString_Insert_EndOfString);
while (*++addr)
{
DoMethod(obj, MUIM_BetterString_Insert, ", ", MUIV_BetterString_Insert_EndOfString);
DoMethod(obj, MUIM_BetterString_Insert, *addr, MUIV_BetterString_Insert_EndOfString);
}
}
///
/// AllocReqText
// Prepare multi-line text for requesters, converts \n to line breaks
char *AllocReqText(char *s)
{
char *d, *reqtext;
d = reqtext = calloc(strlen(s)+1, 1);
while (*s)
if (*s == '\\' && s[1] == 'n') { *d++ = '\n'; s++; s++; }
else *d++ = *s++;
return reqtext;
}
///
/// putCharFunc
// Hook used by FormatString()
void SAVEDS ASM putCharFunc(REG(a0, struct Hook *hook), REG(a1, char c), REG(a2, struct Locale *locale))
{
char **tmp;
((char *)hook->h_Data)[0] = c;
tmp = (char **)(&hook->h_Data);
(*tmp)++;
}
MakeHook(putCharHook, putCharFunc);
///
/// SPrintF
// sprintf() replacement with Locale support
void SPrintF(char *outstr, char *fmtstr, ...)
{
struct Hook hook;
#ifdef __PPC__
va_list ap;
ULONG arg[32];
int args = 0, i;
for (i=0; fmtstr[i] != '\0'; i++) {
if (fmtstr[i] == '%' && fmtstr[i+1] != '%') args++;
}
va_start(ap, fmtstr);
for (i=0; i<args; i++) {
arg[i] = va_arg(ap, ULONG);
}
va_end(ap);
#endif
InitHook(&hook, putCharFunc, outstr);
#ifdef __PPC__
FormatString(G->Locale, fmtstr, &arg[0], &hook);
#else
FormatString(G->Locale, fmtstr, &fmtstr+1, &hook);
#endif
}
///